package com.heo.server;

import com.heo.pojo.DeviceInfoEntity;
import com.heo.pojo.DeviceModelEntity;
import com.heo.pojo.JsonArgs;
import com.heo.pojo.OrgInfoEntity;
import com.heo.pojo.StatusDictEntity;
import com.heo.pub.ApplicationContextUtil;
import com.heo.pub.DictEnum;
import com.heo.service.DeviceInfoService;
import com.heo.service.DeviceModelService;
import com.heo.service.OrgInfoService;
import com.heo.service.StatusDictService;
import com.heo.util.GsonUtils;
import com.heo.util.NettyChannelSlotMapUtils;
import com.heo.util.Utils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

@Component
@Scope("prototype")
public class NettyServerSlotHandle extends SimpleChannelInboundHandler<String> {

	private static final Logger logger = Logger.getLogger(NettyServerSlotHandle.class);

	public ChannelHandlerContext mCtx;
	private String macAddress = null;
	private String deviceImei = null;
	private String appId = "";
	private String callUrl = "";
	private int lastOption;
	private Integer t = null;
	private int xt = 120;
	private long sendTime = 0;
	private Map<String, StatusDictEntity> statusDictMap;

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		this.mCtx = ctx;
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (Utils.checkNull(macAddress)) {
			NettyChannelSlotMapUtils.remove(appId, deviceImei);
		}
		logger.info(macAddress + " userEventTriggered channel close");
		ctx.close();
	}

	@Override
	public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
		try {
			String jsonString = msg;
			Map<String, Object> rspJsonMap = null;
			logger.info("macAddress = " + macAddress + ", read message = " + jsonString);
			JsonArgs jsonArgs = (JsonArgs) GsonUtils.jsonToObject(jsonString, JsonArgs.class);
			if (jsonArgs != null) {
				Integer option = jsonArgs.getO();
				if (Utils.checkNull(jsonArgs.getM())) {
					macAddress = jsonArgs.getM();
				}
				if (Utils.checkNull(option)) {
					rspJsonMap = new HashMap<String, Object>();
					rspJsonMap.put("o", option);
					switch (option) {
					case 1:
						lastOption = option;
						if (!Utils.checkNull(macAddress)) {
							throw new Exception("设备不存在请联系管理员!!");
						}
						// 初始化设备，并入库
						DeviceInfoService deviceInfoService = (DeviceInfoService) ApplicationContextUtil
								.getBeanById("deviceInfoService");
						DeviceModelService deviceModelService = (DeviceModelService) ApplicationContextUtil
								.getBeanById("deviceModelService");
						StatusDictService statusDictService = (StatusDictService) ApplicationContextUtil
								.getBeanById("statusDictService");
						OrgInfoService orgInfoService = (OrgInfoService) ApplicationContextUtil
								.getBeanById("orgInfoService");
						DeviceInfoEntity deviceInfo = deviceInfoService.getDeviceInfoMap(macAddress);
						if (deviceInfo == null) {
							throw new Exception(macAddress + "设备不存在请联系管理员!!");
						}
						deviceImei = deviceInfo.getDeviceImei();
						DeviceModelEntity deviceModel = deviceModelService
								.getDeviceModelMap(deviceInfo.getDeviceModelId());
						statusDictMap = statusDictService.getStatusDictMap(deviceModel.getDeviceModelId());
						// NettyChannelMapUtils.getInstance().add(macAddress, this);
						deviceInfoService.initDeviceInfo(jsonArgs);
						OrgInfoEntity orgInfoEntity = orgInfoService.getByKey(deviceInfo.getDeviceImei());
					    appId = orgInfoEntity.getAppId();
					    callUrl = orgInfoEntity.getCallUrl();
						NettyChannelSlotMapUtils.add(appId, deviceInfo.getDeviceImei(),
								deviceInfo.getDeviceChannelNum(), Utils.getShort(deviceModel.getDeviceModel()),
								ctx.channel());
						boolean startWasher = true;
						t = jsonArgs.getT();
						// 如果是投币工作
						if (Utils.checkNull(t)) {
							NettyChannelSlotMapUtils.outsideController(appId, deviceInfo.getDeviceImei(), 0,
									DictEnum.CallBackType.STATUS_REPORT, t, callUrl, rspJsonMap);
							startWasher = false;
						}

						NettyChannelSlotMapUtils.initTcpOption(jsonArgs, startWasher, appId, deviceInfo.getDeviceImei(),
								0, DictEnum.CallBackType.STATUS_REPORT, callUrl);
						rspJsonMap.put("t", 120); // 心跳时间
						rspJsonMap.put("n", 3); // 心跳次数重启
						rspJsonMap.put("v", 4); // 获取指令v*10秒没有检测到启动就重启
						rspJsonMap.put("y", 2); // y
												// 数据类型：数值，长度小于7字符，描述：连续投币延时时间，单位=秒，分辨率1秒，默认10秒
						rspJsonMap.put("i", 30); // 心跳超时时间
						sendMessage(rspJsonMap);

						break;
					case 2:
						if (Utils.checkNull(jsonArgs.getS())) {
							if (NettyChannelSlotMapUtils.get(appId, deviceImei) == null) {
								// NettyChannelMapUtils.getInstance().add(macAddress, this);
								NettyChannelSlotMapUtils.remove(appId, deviceImei);
								close();
							}
							boolean initDeriveWashing = false;
							// 如果不是重复心跳 且不是外部投币的请求下， 需要初始化工作中的设备
							if (lastOption != 2 && !Utils.checkNull(t)) {
								initDeriveWashing = true;
							}
							lastOption = option;
							t = null;
							// optionService.heartbeat(macAddress,
							// jsonArgs.getS(), initDeriveWashing,
							// rspJsonMap, xt);
							NettyChannelSlotMapUtils.heartbeat(jsonArgs.getS(), appId, deviceImei, 0,
									DictEnum.CallBackType.STATUS_REPORT, callUrl);
//							String xts = Utils.getStr(rspJsonMap.get("t"));
//							if (Utils.checkNull(xts)) {
//								xt = Utils.getInt(xts);
//							}
							sendMessage(rspJsonMap);
						} else {
							throw new Exception("参数不正确");
						}
						break;
					case 3:
						lastOption = option;
						rspJsonMap.put("t", 150); // 心跳时间
						if (!Utils.checkNull(macAddress)) {
							throw new Exception("设备不存在请联系管理员!!");
						}
						t = jsonArgs.getT();
						// 如果是投币工作
						if (Utils.checkNull(t)) {
							// optionService.outsideController(macAddress, t, rspJsonMap);
							NettyChannelSlotMapUtils.outsideController(appId, deviceImei, 0,
									DictEnum.CallBackType.STATUS_REPORT, t, callUrl, rspJsonMap);
							rspJsonMap.put("t", 120);
							sendMessage(rspJsonMap);
							break;
						}

						t = null;

						String errorCode = jsonArgs.getE();
						// 如果是投币工作
						if (Utils.checkNull(errorCode)) {
							// optionService.errorCodeOption(macAddress, errorCode);
							NettyChannelSlotMapUtils.errorCodeOption(appId, deviceImei, 0,
									DictEnum.CallBackType.STATUS_REPORT, callUrl, errorCode, statusDictMap);
							rspJsonMap.put("t", 150); // 错误心跳
							sendMessage(rspJsonMap);
							break;
						}

						Integer s = jsonArgs.getS();
						if (Utils.checkNull(s)) {
							sendTime = 0;
							xt = 100;
							String cmd = "";
							if (s == 0) {
								cmd = "00";
							} else if (s == 3) {
								cmd = "03";
							} else if (s == 1) {
								cmd = "01";
							}
							NettyChannelSlotMapUtils.callBackSendStatus(appId, deviceImei, 0,
									DictEnum.CallBackType.STATUS_REPORT, cmd, callUrl, statusDictMap);
							// optionService.deviceController(macAddress, s, rspJsonMap);
							rspJsonMap.put("t", 120);
							sendMessage(rspJsonMap);
						}
						break;
					}
				} else {
					throw new Exception("设备不存在请联系管理员!!");
				}
			} else {
				throw new Exception("参数不正确");
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
			NettyChannelSlotMapUtils.remove(appId, deviceImei);
			close();
		}
	}

	/**
	 * 发送消息
	 * 
	 * @param rspJsonMap
	 * @throws Exception
	 */
	public synchronized void sendMessage(Map<String, Object> rspJsonMap) throws Exception {
		if (rspJsonMap != null && rspJsonMap.size() > 0 && mCtx != null) {
			// Thread.sleep(2000);
			String rspJson = GsonUtils.objectToJson(rspJsonMap);
			// ByteBuf out = string2ByteBuf(rspJson);
			if (mCtx != null && mCtx.channel().isActive()) {
				if (mCtx.channel().isWritable()) {
					if (Utils.checkNull(rspJson)) {
						mCtx.writeAndFlush(rspJson + "\n").addListener(
								future -> {
									if (future.isSuccess()) {
										logger.info("macAddress=" + macAddress + ", send message = " + rspJson);
									}
								});
					}
				} else {
					try {
						mCtx.writeAndFlush(rspJson + "\n").sync();
						logger.info("macAddress=" + macAddress + ", send message = " + rspJson);
					} catch (InterruptedException e) {
						close();
					}
				}
			} else {
				close();
			}
		}
	}

	/**
	 * 发送消息
	 * 
	 * @param rspJsonMap
	 * @throws Exception
	 */
	public synchronized void sendMessage(String rspJson) throws Exception {
		if (mCtx != null && Utils.checkNull(rspJson)) {
			long time = System.currentTimeMillis();
			if (sendTime == 0) {
				sendTime = System.currentTimeMillis();

			} else if ((time - sendTime) >= 40000) {
				NettyChannelSlotMapUtils.remove(appId, deviceImei);
				close();
			}
			xt = 35;
			lastOption = 4;
			t = null;
			// ByteBuf out = string2ByteBuf(rspJson);
			if (mCtx != null && mCtx.channel().isActive()) {
				if (mCtx.channel().isWritable()) {
					if (Utils.checkNull(rspJson)) {
						mCtx.writeAndFlush(rspJson + "\n").addListener(
								future -> {
									if (future.isSuccess()) {
										logger.info("macAddress=" + macAddress + ", send message = " + rspJson);
									}
								});
					}
				} else {
					try {
						mCtx.writeAndFlush(rspJson + "\n").sync();
						logger.info("macAddress=" + macAddress + ", send message = " + rspJson);
					} catch (InterruptedException e) {
						close();
					}
				}
			} else {
				close();
			}
		}
	}

	public void close() throws IOException {
		if (mCtx != null) {
			mCtx.close();
			mCtx = null;
//			if (isRemove) {
				logger.info(macAddress + " connect close");
//			} else {
//				logger.info("old:" + macAddress + " connect close");
//			}
		}
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		super.channelReadComplete(ctx);
		// 刷新挂起的数据到远端
		ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		logger.info(cause.getMessage());
		if (Utils.checkNull(macAddress)) {
			NettyChannelSlotMapUtils.remove(appId, deviceImei);
		}
		logger.info(macAddress + " exceptionCaught channel close");
		ctx.close();
	}
}
